package org.qianji.goosql.cond;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.qianji.goosql.exception.ConditionException;

/**
 * 与查询条件，同时过滤掉重复条件，并剥离多层与嵌套。
 * 
 * @author gmz
 * 
 */
public class And extends AbstractCondition {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1913181742690276466L;

	private List<Condition> conds = new ArrayList<Condition>();

	/**
	 * 构造与查询条件。
	 * 
	 * @param conds
	 *            {@link Condition} 查询条件数组
	 */
	public And(Condition... conds) {
		super();
		if (conds == null || conds.length == 0) {
			throw new NullPointerException("conds can't be null");
		}
		for (Condition cond : conds) {
			if (cond != null) {
				if (cond instanceof And) {
					List<Condition> cl = ((And) cond).getConds();
					for (Condition c : cl) {
						if (c != null && !this.conds.contains(c)) {
							this.conds.add(c);
						}
					}
				} else if (!this.conds.contains(cond)) {
					this.conds.add(cond);
				}
			}
		}
		assertEmpty();
	}

	/**
	 * 获取旧查询条件。
	 * 
	 * @return {@link List List&lt;Condition&gt;} 查询条件
	 */
	public List<Condition> getConds() {
		return conds;
	}

	/**
	 * 获取大小，即AND起来的查询条件数。
	 * 
	 * @return {@link java.lang.Integer int} 查询条件数
	 */
	public int size() {
		return conds.size();
	}

	private void assertEmpty() {
		if (size() == 0) {
			throw new ConditionException("And Condition is empty");
		}
	}

	@Override
	public String toSql() {
		assertEmpty();
		int size = size();
		if (size == 1) {
			return conds.get(0).toSql();
		}
		StringBuffer cond = new StringBuffer();
		cond.append("(").append(conds.get(0).toSql()).append(")");
		for (int i = 1; i < size; i++) {
			cond.append(" AND (").append(conds.get(i).toSql()).append(")");
		}
		return cond.toString();
	}

	@Override
	public List<Object> getPlacedParameters() {
		assertEmpty();
		List<Object> ppl = new ArrayList<Object>();
		for (Condition cond : conds) {
			ppl.addAll(cond.getPlacedParameters());
		}
		return ppl;
	}

	@Override
	public Map<String, Object> getNamedParameters() {
		assertEmpty();
		Map<String, Object> npm = new HashMap<String, Object>();
		for (Condition cond : conds) {
			npm.putAll(cond.getNamedParameters());
		}
		return npm;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null || !(obj instanceof And)) {
			return false;
		}
		And other = (And) obj;
		if (size() == other.size()) {
			for (Condition cond : other.getConds()) {
				if (!conds.contains(cond)) {
					return false;
				}
			}
			return true;
		}
		return false;
	}

	@Override
	public int hashCode() {
		int hc = 37 * 17 + "AND".hashCode();
		for (Condition cond : conds) {
			hc = 37 * hc + cond.hashCode();
		}
		return hc;
	}

	@Override
	public String toString() {
		return toSql();
	}

}
